﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TestApplication.business.api;
using TestApplication.business.src;
using System.Threading;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Media.Imaging;
using TestApplication.control;
using System.Windows;
using Emgu.CV;
using System.Runtime.InteropServices;
using TestApplication.usercontrols;
using TestApplication.business.src.Types;
using System.Windows.Controls;
using System.Windows.Input;

namespace TestApplication.business.src
{
    public sealed class CaptureModel : INotifyPropertyChanged
    {
        private static Boolean _brainResultReceived;
        private static Boolean _movementBrainResultReceived;
        private static Boolean _capturedImageChanged;
        private static Bitmap _image;
        private static MainWindow view;
        private static AvailablePlugins pluginList;
        public event PropertyChangedEventHandler PropertyChanged;
        private static readonly CaptureModel instance = new CaptureModel();
        private static Capture capture;
        private static MovementBrain movementBrain;
        private static Thread movementBrainThread;
        private static bool pluginStarted;
        private static readonly ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim();
        private static PluginBarControl pluginBarControl;
        private static string currentRunningPlugin;
        private static string previousButtonContent;


        #region Properties

        public string CurrentRunningPlugin
        {
            get { return CaptureModel.currentRunningPlugin; }
            set { CaptureModel.currentRunningPlugin = value; }
        }

        public Bitmap Image
        {
            
            get
            {
                rwlock.EnterWriteLock();
                try
                {
                    //Console.WriteLine(DateTime.Now.Ticks +" Thread is reading Image: " + Thread.CurrentThread.Name);
                    return new Bitmap(_image);
                }
                finally 
                {
                    rwlock.ExitWriteLock(); 
                }
            }
            set
            {
                rwlock.EnterWriteLock();
                try
                {
                    //Console.WriteLine(DateTime.Now.Ticks + " Thread is writing Image: " + Thread.CurrentThread.Name);
                    _image = value;
                    if (value != null)
                    {
                        OnPropertyChanged(this, new PropertyChangedEventArgs("Image"));
                        if (movementBrain != null && !movementBrain.NewImageFromWebcam)
                        {
                            movementBrain.NewImageFromWebcam = true;
                        }
                    }
                }
                finally
                {
                    rwlock.ExitWriteLock();

                }
            }
        }


        public Boolean CapturedImageChanged
        {
            get { return _capturedImageChanged; }
            set { _capturedImageChanged = value; }
        }



        public Boolean MovementBrainResultReceived
        {
            get { return _movementBrainResultReceived; }
            set { _movementBrainResultReceived = value; }
        }

        public Boolean BrainResultReceived
        {
            get { return _brainResultReceived; }
            set { _brainResultReceived = value; }
        }

        public static CaptureModel Instance
        {
            get
            {
                return CaptureModel.instance;
            }
        }

        public AvailablePlugins PluginList
        {
            get { return CaptureModel.pluginList; }
            set { CaptureModel.pluginList = value; }
        }

        public MainWindow View
        {
            get { return CaptureModel.view; }
            set { CaptureModel.view = value; }
        }

        #endregion

        private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(sender, e);
            }
        }

        public CaptureModel()
        {         
                capture = new Capture(2);
                capture.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_HEIGHT, 480);
                capture.SetCaptureProperty(Emgu.CV.CvEnum.CAP_PROP.CV_CAP_PROP_FRAME_WIDTH, 640);
                _image = ImageProcessing.NewEmptyImage(320, 240, Color.Black);
        }


        public void InitializePlugin()
        {
            this.PluginList.Find(currentRunningPlugin).Instance.Initialize();
        }

        
        public void StartWebcam()
        {
            pluginStarted = true;

        }

        public void InitMovementBrain()
        {
            ButtonBarControl buttonBar = null;
            for (int i = 0; i < view.pluginView.MainGrid.Children.Count; i++)
            {
                if (view.pluginView.MainGrid.Children[i].GetType() == typeof(ButtonBarControl))
                {
                    buttonBar = (ButtonBarControl)view.pluginView.MainGrid.Children[i];
                }
                else if (view.pluginView.MainGrid.Children[i].GetType() == typeof(PluginBarControl))
                {
                    pluginBarControl = (PluginBarControl)view.pluginView.MainGrid.Children[i];
                }
            }
            movementBrain = new MovementBrain(pluginBarControl, buttonBar, view.pluginView.WebcamControl.WebcamImage);
            movementBrainThread = new Thread(new ThreadStart(movementBrain.Run));
            movementBrainThread.Name = "MovementBrainThread";
            movementBrain.BarEvent += new PropertyChangedEventHandler(movementBrain_Event);
            movementBrain.RunThread = true;
        }

        public void StopWebcam()
        {
            pluginStarted = false;
            //Image = ImageProcessing.NewEmptyImage(320, 240, Color.Black);
        }

        public void movementBrain_Event(object sender, PropertyChangedEventArgs e)
        {
            string[] commands = e.PropertyName.Split(',');
            if (commands[0] == "SIDEBAR")
            {
                if (commands[1] == "show")
                {
                    pluginBarControl.Dispatcher.BeginInvoke(new Action(delegate() { pluginBarControl.Visibility = Visibility.Visible; }));
                }
                else if (commands[1] == "disable")
                {
                    pluginBarControl.Dispatcher.BeginInvoke(new Action(delegate() { pluginBarControl.disableAllButtons(false); }));
                }
                else if (commands[1] == "enable")
                {
                    pluginBarControl.Dispatcher.BeginInvoke(new Action(delegate() { pluginBarControl.disableAllButtons(true); }));
                }
                else if (commands[1] == "hide")
                {
                    pluginBarControl.Dispatcher.BeginInvoke(new Action(delegate() { pluginBarControl.Visibility = Visibility.Hidden; }));
                }
                else if (commands[1] == "reset")
                {
                    pluginBarControl.Dispatcher.BeginInvoke(new Action(delegate() { ((Button)pluginBarControl.buttonStack.Children[Convert.ToInt32(commands[2]) + 1]).Content = previousButtonContent; }));
                }
                else
                {
                    Console.WriteLine("Button from sidebar pressed:" + commands[1]);
                    pluginBarControl.Dispatcher.BeginInvoke(new Action(delegate() { Button buttonToPress = (Button)pluginBarControl.buttonStack.Children[Convert.ToInt32(commands[1]) + 1]; buttonToPress.RaiseEvent(new RoutedEventArgs(Button.ClickEvent)); if (previousButtonContent != "Pressed") { previousButtonContent = (string)buttonToPress.Content; buttonToPress.Content = "Pressed"; } }));
                }
            }
            else if (commands[0] == "BUTTON")
            {
                int index = Convert.ToInt32(commands[1]);
                switch (index)
                {
                    case 0:
                        this.PluginList.Find(currentRunningPlugin).Instance.StartPlugin();
                        break;
                    case 1:
                        this.PluginList.Find(currentRunningPlugin).Instance.StopPlugin();
                        break;
                    case 2:
                        this.PluginList.Find(currentRunningPlugin).Instance.StopPlugin();
                        movementBrain.RunThread = false;
                        StopWebcam();
                        this.View.Dispatcher.BeginInvoke(new Action(delegate() { this.View.GoBack(); }));
                        break;
                    default:
                        Console.WriteLine("Button index does not exist");
                        break;
                }
            }
        }

        public void ThreadRun()
        {
            while (true)
            {
                if (pluginStarted)
                {
                    Bitmap image = capture.QueryFrame().Bitmap;
                    image.RotateFlip(RotateFlipType.RotateNoneFlipX);
                    CaptureModel.Instance.Image = image;

                    if (movementBrainThread != null && !movementBrainThread.IsAlive && movementBrainThread.ThreadState != ThreadState.Stopped)
                    {
                        movementBrainThread.Start();
                    }
                }
                Thread.Sleep(30);
            }
        }
    }
}
